﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;

namespace ArgusLib.Controls
{
	public class FlagsListBox<T> : System.Windows.Forms.CheckedListBox
		where T:struct
	{
		LocalizableEnumAttribute[] locEnumAttr;

		public FlagsListBox()
			: base()
		{
			Type type = typeof(T);
			if (type.IsEnum == false || type.GetCustomAttributes(typeof(FlagsAttribute), false).Length == 0)
				throw new GenericTypeParameterNotSupportetException("T must be an enumeration with FlagsAttribute declared on it.");
			this.BackColor = Color.Black;
			this.ForeColor = Color.White;
			this.CheckOnClick = true;

			object[] attributes = type.GetCustomAttributes(typeof(LocalizableEnumAttribute), false);
			List<LocalizableEnumAttribute> locAttributes = new List<LocalizableEnumAttribute>();
			foreach (object attr in attributes)
				locAttributes.Add((LocalizableEnumAttribute)attr);
			this.locEnumAttr = locAttributes.ToArray();

			this.Populate();
		}

		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public T SelectedFlags
		{
			get
			{
				long flags = 0;
				foreach (T flag in this.CheckedItems)
					flags |= (long)Convert.ToInt64(flag);
				return (T)Enum.ToObject(typeof(T), flags);
			}
			set
			{
				long flags = (long)Convert.ToInt64(value);
				this.BeginUpdate();
				for (int i = 0; i < this.Items.Count; i++)
				{
					long flag = (long)Convert.ToInt64(this.Items[i]);
					this.SetItemChecked(i, (flags & flag) == flag);
				}
				this.EndUpdate();
			}
		}

		public T[] GetSelectedFlags()
		{
			T[] RetVal = new T[this.CheckedItems.Count];
			this.CheckedItems.CopyTo(RetVal, 0);
			return RetVal;
		}

		protected virtual void Populate()
		{
			T[] values = (T[])Enum.GetValues(typeof(T));

			this.BeginUpdate();
			this.Items.Clear();

			foreach (T value in values)
			{
				if (this.IsValidValue(value) == true)
					this.Items.Add(value);
			}

			this.EndUpdate();
		}

		[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public new CheckedListBox.ObjectCollection Items
		{
			get { return base.Items; }
		}

		protected virtual bool IsValidValue(T value)
		{
			if (Enum.IsDefined(typeof(T), value) == false)
				return false;
			if ((long)Convert.ToInt64(value) == 0)
				return false;
			return true;
		}

		protected virtual string FormatValue(T value)
		{
			foreach (LocalizableEnumAttribute attr in this.locEnumAttr)
			{
				string text = attr.GetLocalization(value);
				if (string.IsNullOrEmpty(text) == false)
				{
					return text;
				}
			}
			return null;
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		protected override void OnFormat(ListControlConvertEventArgs e)
		{
			string text = this.FormatValue((T)e.ListItem);
			if (text != null)
				e.Value = text;
			base.OnFormat(e);
		}
	}
}
